﻿#include "lottieplayer.h"
#include "ui_lottieplayer.h"

#include <QListView>
#include <QMessageBox>
#include <QEvent>
#include <QKeyEvent>
#include <QMimeData>
#include <QFileInfo>
#include <QUrl>
#include <QClipboard>
#include <QFileDialog>
#include <QMouseEvent>

#include "loaddialog.h"
#include "exportgifdialog.h"
#include "aboutdialog.h"

LottiePlayer::LottiePlayer(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::LottiePlayer)
{
    ui->setupUi(this);
    ui->widget_mark->hide();
    ui->comboBox_speed->setView(new QListView());
    ui->comboBox_start->setView(new QListView());
    ui->comboBox_end->setView(new QListView());
    ui->pushButton_pause->hide();
    //设置动画窗口
    m_lottieWidget = new QtLottieWidget;
    m_lottieWidget->installEventFilter(this);
    ui->horizontalLayout_show->addWidget(m_lottieWidget);
    connect(m_lottieWidget, &QtLottieWidget::sigFrameChange,
        this, [this](int frame, int ms) {
        QString curTime = formatTime(ms);
        ui->label_time_line->setText(QString("%1 / %2 (%3/%4)")
            .arg(curTime).arg(m_allTime).arg(frame + 1).arg(m_allFrame));
        ui->horizontalSlider_pos->blockSignals(true);
        ui->horizontalSlider_pos->setValue(frame);
        ui->horizontalSlider_pos->blockSignals(false);
    });
    connect(m_lottieWidget, &QtLottieWidget::sigFinished, this, [this] {
        ui->pushButton_play->show();
        ui->pushButton_pause->hide();
        if(m_showFullscreen)
            ui->pushButton_fullscreen->setChecked(false);
        //menu
        ui->action_play->setEnabled(true);
        ui->action_pause->setEnabled(false);
    });
    //允许拖拽
    setAcceptDrops(true);
    //菜单设置
    //menu_file
    connect(ui->action_file, &QAction::triggered,
        this, [this] { loadShowDlg(true); });
    connect(ui->action_data, &QAction::triggered,
        this, [this] { loadShowDlg(false); });
    connect(ui->action_gif, &QAction::triggered,
        this, &LottiePlayer::on_pushButton_load_clicked);
    connect(ui->action_about, &QAction::triggered, this, []{
        AboutDialog dlg;
        dlg.exec();
    });
    connect(ui->action_exit, &QAction::triggered,
        this, &LottiePlayer::close);
    //menu_ctrl
    connect(ui->action_play, &QAction::triggered,
        this, &LottiePlayer::on_pushButton_play_clicked);
    ui->action_pause->setEnabled(false);
    connect(ui->action_pause, &QAction::triggered,
        this, &LottiePlayer::on_pushButton_pause_clicked);
    connect(ui->action_stop, &QAction::triggered,
        this, &LottiePlayer::on_pushButton_stop_clicked);
    QAction* actList[] = { ui->action_X_0_25,
        ui->action_X_0_50, ui->action_X_0_75, ui->action_X_1_0,
        ui->action_X_1_5, ui->action_X_2_0, ui->action_X_3_0};
    int actNum = _countof(actList);
    for (int i = 0;  i < actNum; ++i) {
        connect(actList[i], &QAction::triggered, this, [this, i] {
            ui->comboBox_speed->setCurrentIndex(i);
        });
    }
    ui->action_X_1_0->setChecked(true);
    //menu_mode
    connect(ui->action_loop, &QAction::triggered,
        ui->pushButton_loop, &QPushButton::setChecked);
    connect(ui->action_reverse, &QAction::triggered,
        ui->pushButton_reverse, &QPushButton::setChecked);
    connect(ui->action_full, &QAction::triggered,
        ui->pushButton_fullscreen, &QPushButton::setChecked);
    //menu_shot
    connect(ui->action_org_copy, &QAction::triggered, this, [this] {
        QImage img = m_lottieWidget->getDefaultImage();
        saveScreenshot(img, false);
    });
    connect(ui->action_org_save, &QAction::triggered, this, [this] {
        QImage img = m_lottieWidget->getDefaultImage();
        saveScreenshot(img, true);
    });
    connect(ui->action_real_copy, &QAction::triggered, this, [this] {
        QImage img = m_lottieWidget->getImage();
        saveScreenshot(img, false);
    });
    connect(ui->action_real_save, &QAction::triggered, this, [this] {
        QImage img = m_lottieWidget->getImage();
        saveScreenshot(img, true);
    });

    //状态栏设置
    m_statusText = u8"未加载动画";
    ui->statusbar->showMessage(m_statusText);
    connect(ui->statusbar, &QStatusBar::messageChanged, this,
        [this](const QString &message){
        if(message.isEmpty() && !m_statusText.isEmpty())
            ui->statusbar->showMessage(m_statusText);
    });
}

LottiePlayer::~LottiePlayer()
{
    m_lottieWidget->unload();
    delete ui;
}

void LottiePlayer::dragEnterEvent(QDragEnterEvent *event)
{
    const QMimeData *mimeData = event->mimeData();
    if(mimeData->hasUrls())
    {
        QList<QUrl> urls = mimeData->urls();
        if(urls.count() == 1) {
            QFileInfo info(urls[0].toLocalFile());
            if(!info.isDir()) {
                event->acceptProposedAction();
                event->setDropAction(Qt::LinkAction);
                event->accept();
                return;
            }
        }
    }
    event->ignore();
}

void LottiePlayer::dropEvent(QDropEvent *event)
{
    const QMimeData *mimeData = event->mimeData();
    if(mimeData->hasUrls())
    {
        QList<QUrl> urls = mimeData->urls();
        if(urls.count() == 1) {
            QFileInfo info(urls[0].toLocalFile());
            if(!info.isDir()) {
                if(!m_lottieWidget->loadFromFile(info.absoluteFilePath()))
                    return;
                initLoaded(info.absoluteFilePath());
            }
        }
    }
}

void LottiePlayer::on_horizontalSlider_pos_valueChanged(int value)
{
    m_lottieWidget->setCurFrame(value);
}

void LottiePlayer::on_comboBox_speed_currentTextChanged(const QString &text)
{
    QString speed = text;
    speed.remove(" X");
    float curSpeed = speed.toFloat();
    on_pushButton_stop_clicked();
    m_lottieWidget->setSpeed(curSpeed);
    //menu
    QAction* actList[] = { ui->action_X_0_25,
        ui->action_X_0_50, ui->action_X_0_75, ui->action_X_1_0,
        ui->action_X_1_5, ui->action_X_2_0, ui->action_X_3_0};
    int actNum = _countof(actList);
    int index = ui->comboBox_speed->currentIndex();
    for (int i = 0; i < actNum; ++i) {
        actList[i]->setChecked(i == index);
    }
}

void LottiePlayer::on_pushButton_play_clicked()
{
    if(!m_lottieWidget->isLoaded()) {
        on_pushButton_load_clicked();
        return;
    }
    if(m_lottieWidget->resume()) {
        ui->pushButton_play->hide();
        ui->pushButton_pause->show();
        //menu
        ui->action_play->setEnabled(false);
        ui->action_pause->setEnabled(true);
    }
}

void LottiePlayer::on_pushButton_pause_clicked()
{
    if(m_lottieWidget->pause()) {
        ui->pushButton_play->show();
        ui->pushButton_pause->hide();
        //menu
        ui->action_play->setEnabled(true);
        ui->action_pause->setEnabled(false);
    }
}

void LottiePlayer::on_pushButton_stop_clicked()
{
    if(m_lottieWidget->stop()) {
        ui->pushButton_play->show();
        ui->pushButton_pause->hide();
        ui->horizontalSlider_pos->setValue(0);
        //menu
        ui->action_play->setEnabled(true);
        ui->action_pause->setEnabled(false);
    }
}

void LottiePlayer::on_pushButton_load_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(
        this, u8"选择Lottie动画文件", QString(), u8"动画文件 (*.*)");
    if(fileName.isEmpty())
        return;
    QFileInfo fileInfo(fileName);
    if(!fileInfo.exists()) {
        QMessageBox::information(this, u8"提示", u8"请选择有效动画文件");
        return;
    }
    if(!m_lottieWidget->loadFromFile(fileName)) {
        QMessageBox::information(this, u8"提示", u8"无法加载指定文件");
        return;
    }
    initLoaded(fileInfo.absoluteFilePath());
}

void LottiePlayer::on_pushButton_gif_clicked()
{
    if(!m_lottieWidget->isLoaded()) {
        QMessageBox::information(this, u8"提示", u8"请先加载lottie动画");
        return;
    }
    ExportGifDialog dlg;
    dlg.setDefautlSize(m_lottieWidget->getDefaultSize());
    if(dlg.exec() != QDialog::Accepted)
        return;
    //导出GIF文件
    m_lottieWidget->exportGif(
        dlg.m_exportFile, dlg.m_exportBgColor,
        dlg.m_exportSize,dlg.m_allowAlpha);
}

void LottiePlayer::on_pushButton_loop_toggled(bool checked)
{
    if(checked) {
        m_lottieWidget->setLoopCount(0);
    } else {
        m_lottieWidget->setLoopCount(1);
    }
    //menu
    ui->action_loop->setChecked(checked);
}

void LottiePlayer::on_pushButton_reverse_toggled(bool checked)
{
    if(checked) {
        m_lottieWidget->setRepeatMode(QtLottieWidget::RM_Reverse);
    } else {
        m_lottieWidget->setRepeatMode(QtLottieWidget::RM_Restart);
    }
    //menu
    ui->action_reverse->setChecked(checked);
}

void LottiePlayer::on_pushButton_fullscreen_toggled(bool )
{
    if(!m_lottieWidget->isLoaded()) {
        ui->pushButton_fullscreen->setChecked(false);
        //menu
        ui->action_full->setChecked(false);
        return;
    }
    //全屏显示
    if(m_showFullscreen) {
        this->show();
        ui->horizontalLayout_show->addWidget(m_lottieWidget);
    } else {
        ui->horizontalLayout_show->removeWidget(m_lottieWidget);
        m_lottieWidget->setParent(nullptr);
        m_lottieWidget->showFullScreen();
        this->hide();
    }
    m_showFullscreen = !m_showFullscreen;
    ui->pushButton_fullscreen->setChecked(m_showFullscreen);
    //menu
    ui->action_full->setChecked(m_showFullscreen);
}

QString LottiePlayer::formatTime(int ms)
{
    int ss = 1000;
    int mi = ss * 60;
    int hh = mi * 60;
    //int dd = hh * 24;
    //int day = ms / dd;
    //ms %= dd;
    int hour = ms / hh;
    ms %= hh;
    int minute = ms / mi;
    ms %= mi;
    int second = ms / ss;
    int milliSecond = ms % ss;

    QString hou = QString::number(hour, 10).rightJustified(2, '0');
    QString min = QString::number(minute, 10).rightJustified(2, '0');
    QString sec = QString::number(second, 10).rightJustified(2, '0');
    QString msec = QString::number(milliSecond, 10).rightJustified(3, '0');

    return QString("%1:%2:%3.%4").arg(hou, min, sec, msec);
}

void LottiePlayer::initLoaded(const QString &name)
{
    m_statusText = QString(u8"已加载动画:%1").arg(name);
    ui->statusbar->showMessage(m_statusText);
    //初始化时间轴
    int ms = m_lottieWidget->getAllTime() * 1000;
    m_allFrame = m_lottieWidget->getAllFrame();
    m_allTime = formatTime(ms);
    ui->label_time_line->setText(QString("00:00:00 / %1 (0/%2)")
        .arg(m_allTime).arg(m_allFrame));
    ui->horizontalSlider_pos->setRange(0, m_allFrame - 1);
    //获得所有标签
    QStringList marks = m_lottieWidget->getAllMarkers();
    ui->comboBox_start->clear();
    ui->comboBox_end->clear();
    ui->comboBox_start->addItem(u8"[无标签]");
    ui->comboBox_end->addItem(u8"[无标签]");
    ui->comboBox_start->addItems(marks);
    ui->comboBox_end->addItems(marks);
    //初始化按钮
    ui->pushButton_play->show();
    ui->pushButton_pause->hide();
    ui->horizontalSlider_pos->setValue(0);
    //menu
    ui->action_play->setEnabled(true);
    ui->action_pause->setEnabled(false);
}

void LottiePlayer::loadShowDlg(bool fileMode)
{
    //加载文件
    LoadDialog dlg;
    dlg.setLoadMode(fileMode);
    dlg.m_lottieWidget = m_lottieWidget;
    if(dlg.exec() != QDialog::Accepted)
        return;
    initLoaded(dlg.m_lottieName);
}

void LottiePlayer::saveScreenshot(QImage img, bool saveFile)
{
    if(img.isNull())
        return;
    if(saveFile) {
        //保存文件
        QString fileName = QFileDialog::getSaveFileName(
            this, u8"保存图像", QString(), u8"图像文件 (*.png)");
        if(fileName.isEmpty())
            return;
        if(QFileInfo(fileName).suffix().toLower() != "png")
            fileName.append(".png");
        img.save(fileName);
    } else {
        //保存剪贴板
        QClipboard *clipboard = QApplication::clipboard();
        clipboard->setImage(img);
    }
}

bool LottiePlayer::eventFilter(QObject *watched, QEvent *event)
{
    QEvent::Type type = event->type();
    if(watched == m_lottieWidget) {
        if(type == QEvent::MouseButtonDblClick) {
            ui->pushButton_fullscreen->setChecked(
                !ui->pushButton_fullscreen->isChecked());
            return true;
        }
        if(type == QEvent::KeyPress) {
            QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
            if (keyEvent->key() == Qt::Key_Escape) {
                if(m_showFullscreen)
                    ui->pushButton_fullscreen->setChecked(false);
                return true;
            }
        }
        if(type == QEvent::MouseButtonRelease &&
            static_cast<QMouseEvent*>(event)->button()==Qt::RightButton) {
            //右键菜单
            QMenu menu;
            menu.addAction(ui->action_file);
            menu.addAction(ui->action_data);
            menu.addSeparator();

            menu.addAction(ui->action_play);
            menu.addAction(ui->action_pause);
            menu.addAction(ui->action_stop);
            menu.addSeparator();

            menu.addAction(ui->action_org_copy);
            menu.addAction(ui->action_org_save);
            menu.addAction(ui->action_real_copy);
            menu.addAction(ui->action_real_save);
            menu.addSeparator();

            menu.addAction(ui->action_gif);
            menu.addSeparator();

            menu.addAction(ui->action_loop);
            menu.addAction(ui->action_reverse);
            menu.addSeparator();

            menu.addAction(ui->action_full);

            menu.exec(QCursor::pos());
            return true;
        }
    }
    return QWidget::eventFilter(watched, event);
}
